﻿#pragma execution_character_set(“utf-8”)；

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    initUi();
    initData();
    initUiData();
    initConnect();
}

Widget::~Widget()
{
    if (isStartServer) {
        endClient();
    }

    if (isStartMysql) {
        delete mysql;
        mysql = nullptr;
    }

    delete ui;
    ui = nullptr;
}

void Widget::initUi()
{
    ui->setupUi(this);

    top_layout = ui->top_layout;
    center_layout = ui->center_layout;

    total_check_box = new CheckBoxWidget(this);

    add_button = top_layout->findChild<QPushButton *>("add_button");
    delete_button = top_layout->findChild<QPushButton *>("delete_button");

    search_box = ui->search_box_widget;
    add_dialog = new ContactPersonAddDialog(this);
    table_view = center_layout->findChild<QTableView *>("table_view");
}

void Widget::initData()
{
    startClient(); // 启动客户端

    mysql = new MysqlTool(); // 获取 MysqlTool 实例对象

    if (mysql->isSuccessOpenDatabase()) { // Mysql 连接正常时, 使用数据库读取存储数据
        getDatabaseAllData();
        isStartMysql = true;

    } else { // Mysql 连接出错时, 使用 Json 文件读取数据
        getJsonFileAllData();
        isStartMysql = false;

        mysql = nullptr;
    }

    // 以当前时间 ms 作为随机数的种子
    qsrand(QTime::currentTime().msec() + QTime::currentTime().second() * 1000);

    // 按照 ContactPerson 的 ID 从小到大排序
    contact_person_list.sort([=](ContactPerson *person1, ContactPerson *person2) {
        return person1->getId() < person2->getId();
    });

    // 设置标题头的文段
    table_head_text << "ID" << "Name" << "Sex" << "Age" << "Phone" << "Address" << "Operation";
}

void Widget::initUiData()
{
    if (contact_person_list.size() <= 10) {
        setFixedSize(612, 400);
    } else {
        setFixedSize(630, 400);
    }

    // 设置程序窗口大小和程序图标
    setWindowTitle("Blue Address Book");
    setWindowIcon(QIcon(":/image/user.png"));

    // 设置全部复选框为多选状态
    total_check_box->check_box->setTristate(true);

    // 隐藏 TableView 的水平和垂直表头
    table_view->verticalHeader()->hide();
    table_view->horizontalHeader()->hide();

    // 设置 TableView 的数据模型
    data_model = new QStandardItemModel(this);
    // TableView 需要 8 列
    data_model->setColumnCount(8);
    table_view->setModel(data_model);

    // 设置 TableView 的行宽度
    for (int i = 0; i < 8; ++i) {
        if (i == 0) {
            table_view->setColumnWidth(0, 30);
        } else {
            table_view->setColumnWidth(i, 75);
        }
    }
    table_view->setColumnWidth(7, 90);

    // 显示表头的特殊处理(???)(为什么这样写可以正常显示表头)
    QStandardItem *id_item = new QStandardItem("1");
    id_item->setTextAlignment(Qt::AlignCenter);
    data_model->setItem(0, 0, id_item);

    // 设置 TableView 第一行第一列的复选框
    table_view->setIndexWidget(data_model->index(0, 0), total_check_box);
    // 设置 TableView 的表头
    for (int i = 0; i < 7; i++) {
        TableHeadWidget *table_head_widget = new TableHeadWidget(this);
        table_head_widget->setWidth(75);
        table_head_widget->setLabelText(table_head_text.at(i));

        table_view->setIndexWidget(data_model->index(0, i + 1), table_head_widget);
    }

    // 数据填充 TableView
    int row = 1;
    for (list<ContactPerson *>::iterator i = contact_person_list.begin(); i != contact_person_list.end(); ++i) {
        ContactPerson *person = *i;
        addContactPersonUiEvent(row++, person);
    }
}


void Widget::initConnect()
{
    // 删除联系人按钮事件
    connect(delete_button, &QPushButton::clicked, [=]() {
        // TableView 需要删除的行数列表
        list<int> delete_row_list;
        // 数据库需要删除的联系人列表
        list<ContactPerson *> delete_person_list;

        int row = 1;
        for (list<CheckBoxWidget *>::iterator i = check_box_list.begin(); i != check_box_list.end(); ++i) {
            CheckBoxWidget *check_box_widget = *i;
            int contact_person_id = check_box_widget->contact_person_id;

            if (check_box_widget->check_box->isChecked()) {
                // 全部复选框列表删除当前复选框
                check_box_list.remove(check_box_widget);
                // 全部联系人列表中删除当前联系人
                ContactPerson *person = getContactPersonById(contact_person_id);
                if (person != nullptr) {
                    contact_person_list.remove(person);
                }

                delete_row_list.push_back(row);
                delete_person_list.push_back(person);

                // 删除当前联系人相关联的复选框和操作按钮
                delete check_box_widget;
                delete operation_dialog_map[person];
            }
            row++;
        }

        // 降序排序需要删除的行, 避免出现删除行变化的情况
        delete_row_list.sort([](int number1, int number2) {
            return number1 > number2;
        });

        // table_view 删除全部选择的联系人
        for (list<int>::iterator i = delete_row_list.begin(); i != delete_row_list.end(); ++i) {
            int delete_row = *i;
            data_model->removeRow(delete_row);
        }

        checkBoxSelectCount -= delete_row_list.size();

        emit checkBoxStateChange();
        emit contactPersonNumberChange();
        emit deleteContactPerson(delete_person_list);
    });

    // 添加联系人按钮事件
    connect(add_button, &QPushButton::clicked, [=]() {
        add_dialog->exec();
    });

    // 联系人输入框添加完成事件
    connect(add_dialog, &ContactPersonAddDialog::inputComplete, [=]() {
        // 从对话框中联系人的 ID 未确定
        ContactPerson *person = add_dialog->getContactPerson();

        // 从服务端获取新用户的ID
        int userId = getUserId();
        person->setId(userId);

        contact_person_list.push_back(person);
        int row = contact_person_list.size();
        // TableView 添加联系人对应的 Ui 事件
        addContactPersonUiEvent(row, person);

        add_dialog->clear();

        emit addContactPerson(person);
        emit contactPersonNumberChange();
    });

    // total_check_box 总复选框的点击事件
    connect(total_check_box->check_box, &QCheckBox::stateChanged, [=]() {
        Qt::CheckState check_state = total_check_box->check_box->checkState();

        if (check_state == Qt::Unchecked) {
            // 取消全部的复选框
            checkBoxSelectCount = 0;
            for (list<CheckBoxWidget *>::iterator i = check_box_list.begin(); i != check_box_list.end(); ++i) {
                CheckBoxWidget *check_box_widget = *i;
                check_box_widget->check_box->setChecked(false);
            }

        } else if (check_state == Qt::Checked) {
            // 选择全部的复选框
            checkBoxSelectCount = check_box_list.size();
            for (list<CheckBoxWidget *>::iterator i = check_box_list.begin(); i != check_box_list.end(); ++i) {
                CheckBoxWidget *check_box_widget = *i;
                check_box_widget->check_box->setChecked(true);
            }

        } else if (check_state == Qt::PartiallyChecked && checkBoxSelectCount == 0) {
            // 特殊情况的处理
            total_check_box->check_box->setCheckState(Qt::Checked);

            // 选择全部的复选框
            checkBoxSelectCount = check_box_list.size();
            for (list<CheckBoxWidget *>::iterator i = check_box_list.begin(); i != check_box_list.end(); ++i) {
                CheckBoxWidget *check_box_widget = *i;
                check_box_widget->check_box->setChecked(true);
            }
        }

    });

    // 搜索条件更改对应的事件
    connect(search_box, &SearchBoxWidget::opationChange, [=]() {
        search_box->setInputText("");

        showTableViewAllRow();
    });

    // 搜索框输入值发生变化对应的事件
    connect(search_box, &SearchBoxWidget::inputTextChange, [=](QString last_input_text, QString current_input_text) {
        showTableViewAllRow();

        QString choose = search_box->getOpationText();
        QString input_text = search_box->getInputText();

        int row = 1;
        for(list<ContactPerson *>::iterator i = contact_person_list.begin(); i != contact_person_list.end(); ++i) {
            ContactPerson *person = *i;

            bool isCorrelation = false;

            if (choose == QString::fromLocal8Bit("ID")) {
                isCorrelation = QString::fromStdString(to_string(person->getId())).contains(input_text, Qt::CaseSensitive);

            } else if (choose ==QString::fromLocal8Bit("Name")) {
                isCorrelation = QString::fromStdString(person->getName()).contains(input_text, Qt::CaseSensitive);

            } else if (choose ==QString::fromLocal8Bit("Age")) {
                isCorrelation = QString::fromStdString(to_string(person->getAge())).contains(input_text, Qt::CaseSensitive);

            } else if (choose ==QString::fromLocal8Bit("Phone")) {
                isCorrelation = QString::fromStdString(to_string(person->getPhone())).contains(input_text, Qt::CaseSensitive);

            } else if (choose ==QString::fromLocal8Bit("Address")) {
                isCorrelation = QString::fromStdString(person->getAddress()).contains(input_text, Qt::CaseSensitive);
            }

            // 当前行和搜索框的内容没关系, 就隐藏当前行
            table_view->setRowHidden(row++, !isCorrelation);
        }
    });

    // 复选框按钮状态发生更改时对应的事件
    connect(this, &Widget::checkBoxStateChange, [=]() {
        if(checkBoxSelectCount == 0) {
            total_check_box->check_box->setCheckState(Qt::Unchecked);

        } else if (checkBoxSelectCount < check_box_list.size()) {
            total_check_box->check_box->setCheckState(Qt::PartiallyChecked);

        } else {
            total_check_box->check_box->setCheckState(Qt::Checked);
        }
    });

    connect(this, &Widget::contactPersonNumberChange, [=]() {
        if (contact_person_list.size() <= 10) {
            setFixedSize(612, 400);
        } else {
            setFixedSize(630, 400);
        }
    });

    // 添加联系人对应的事件
    connect(this, &Widget::addContactPerson, [=](ContactPerson *person) {
        if (isStartMysql) {
            QSqlQuery query = mysql->query;
            QString sql = "insert into contact_person (id, name, sex, age, phone, address) values (?, ?, ?, ?, ?, ?)";
            query.prepare(sql);

            QString id = QString::fromStdString(to_string(person->getId()));
            QString name = QString::fromStdString(person->getName());
            QString sex = QString::fromStdString(to_string(person->getSex()));
            QString age = QString::fromStdString(to_string(person->getAge()));
            QString phone = QString::fromStdString(to_string(person->getPhone()));
            QString address = QString::fromStdString(person->getAddress());

            query.addBindValue(id);
            query.addBindValue(name);
            query.addBindValue(sex);
            query.addBindValue(age);
            query.addBindValue(phone);
            query.addBindValue(address);

            bool result = query.exec();

            if (result) {
                QMessageBox::information(this, "Tips", "添加成功!");

            } else {
                QMessageBox::information(this, "Tips", "添加失败!");
            }

        } else {
            // 往 JsonArray 中添加联系人数据
            addContactPersonToJsonArray(person);

            writeDataToJson();

            QMessageBox::information(this, "Tips", "添加成功!");
        }
    });

    // 删除联系人对应的事件
    connect(this, &Widget::deleteContactPerson, [=](list<ContactPerson *> delete_person_list) {
        if (delete_person_list.size() == 0) {
            QMessageBox::information(this, "Tips", "未选择删除的联系人!");
            return;

        } else {
            if (isStartMysql) {
                bool result = true;

                for (list<ContactPerson *>::iterator i = delete_person_list.begin(); i != delete_person_list.end(); ++i) {
                    ContactPerson *person = *i;

                    QSqlQuery query = mysql->query;
                    QString sql = "delete from contact_person where id = ?";
                    query.prepare(sql);

                    QString id = QString::fromStdString(to_string(person->getId()));
                    query.addBindValue(id);

                    if (!query.exec()) {
                        result = false;
                    }

                    delete person;
                }

                if (result) {
                    QMessageBox::information(this, "Tips", "删除成功!");

                } else {
                    QMessageBox::information(this, "Tips", "删除失败!");
                }

            } else {
                for (list<ContactPerson *>::iterator i = delete_person_list.begin(); i != delete_person_list.end(); ++i) {
                    deleteContactPersonFromJsonArray(*i);
                }

                writeDataToJson();

                QMessageBox::information(this, "Tips", "删除成功!");
            }
        }
    });

    // 修改联系人对应的事件
    connect(this, &Widget::modifyContactPerson, [=](ContactPerson *person) {
        if (isStartMysql) {
            if (person->getId() <= 0) {
                return;
            }

            QSqlQuery query = mysql->query;
            QString sql = "update contact_person set name = ?, sex = ?, age = ?, phone = ?, address = ? where id = ?";
            query.prepare(sql);

            QString id = QString::fromStdString(to_string(person->getId()));
            QString name = QString::fromStdString(person->getName());
            QString sex = QString::fromStdString(to_string(person->getSex()));
            QString age = QString::fromStdString(to_string(person->getAge()));
            QString phone = QString::fromStdString(to_string(person->getPhone()));
            QString address = QString::fromStdString(person->getAddress());

            query.addBindValue(id);
            query.addBindValue(name);
            query.addBindValue(sex);
            query.addBindValue(age);
            query.addBindValue(phone);
            query.addBindValue(address);

            bool result = query.exec();

            if (result) {
                QMessageBox::information(this, "Tips", "修改成功!");

            } else {
                QMessageBox::information(this, "Tips", "修改失败!");
            }

        } else {
            // 删除 JsonArray 中当前修改的联系人数据
            deleteContactPersonFromJsonArray(person);

            // 往 JsonArray 中添加修改后的联系人数据
            addContactPersonToJsonArray(person);

            writeDataToJson();

            QMessageBox::information(this, "Tips", "修改成功!");
        }
    });
}

ContactPerson *Widget::getContectPerson()
{
    ContactPerson *person = new ContactPerson();

    person->setId(1);
    person->setName("Blue");
    person->setAge(19);
    person->setSex(0);
    person->setPhone(123456789);
    person->setAddress("牧业村");

    return person;
}

void Widget::prinfAllContactPersonInfomation()
{
    for(list<ContactPerson *>::iterator i = contact_person_list.begin(); i != contact_person_list.end(); ++i) {
        ContactPerson *person = *i;

        qDebug() << QString::fromStdString(person->toString());
    }
}

void Widget::addContactPersonUiEvent(int row, ContactPerson *person)
{
    tableViewFillContactPerson(row, person);

    // 设置 table_view 第一列的复选框
    CheckBoxWidget *check_box_widget = new CheckBoxWidget();
    check_box_widget->contact_person_id = person->getId();
    check_box_list.push_back(check_box_widget);
    table_view->setIndexWidget(data_model->index(row, 0), check_box_widget);

    // 设置 table_view 第一列的复选框的点击事件
    connect(check_box_widget->check_box, &QAbstractButton::clicked, [=]() {
        bool isChecked = check_box_widget->check_box->isChecked();

        if (isChecked) {
            checkBoxSelectCount++;

        } else {
            checkBoxSelectCount--;
        }

        emit checkBoxStateChange();
    });


    OperationWidget *operation_widget = new OperationWidget(this);
    // 设置联系人的修改按钮的点击事件
    connect(operation_widget->modify_button, &QPushButton::clicked, [=]() {
        ContactPersonModifyDialog *modify_dialog = new ContactPersonModifyDialog(this, person);
        connect(modify_dialog, &ContactPersonModifyDialog::inputComplete, [=]() {
            int row = getTableRowById(person->getId());
            tableViewFillContactPerson(row, person);

            emit modifyContactPerson(person);
        });

        modify_dialog->exec();
    });
    // 设置 TableView 最后一列的修改按钮
    table_view->setIndexWidget(data_model->index(row, 7), operation_widget);

    operation_dialog_map.insert({person, operation_widget});
}

void Widget::tableViewFillContactPerson(int row , ContactPerson *person)
{
    QStandardItem *id_item = new QStandardItem(QString::fromStdString(to_string(person->getId())));
    id_item->setTextAlignment(Qt::AlignCenter);
    data_model->setItem(row, 1, id_item);

    QStandardItem *name_item = new QStandardItem(QString::fromStdString(person->getName()));
    name_item->setTextAlignment(Qt::AlignCenter);
    data_model->setItem(row, 2, name_item);

    QStandardItem *sex_item = new QStandardItem(QString::fromStdString(person->getSex() == 0 ? "boy" : person->getSex() == 1 ? "girl" : "unknow"));
    sex_item->setTextAlignment(Qt::AlignCenter);
    data_model->setItem(row, 3, sex_item);

    QStandardItem *age_item = new QStandardItem(QString::fromStdString(to_string(person->getAge())));
    age_item->setTextAlignment(Qt::AlignCenter);
    data_model->setItem(row, 4, age_item);

    QStandardItem *phone_item = new QStandardItem(QString::fromStdString(to_string(person->getPhone())));
    phone_item->setTextAlignment(Qt::AlignCenter);
    data_model->setItem(row, 5, phone_item);

    QStandardItem *address_item = new QStandardItem(QString::fromStdString(person->getAddress()));
    address_item->setTextAlignment(Qt::AlignCenter);
    data_model->setItem(row, 6, address_item);
}

int Widget::getTableRowById(int contact_person_id)
{
    int row = 1;

    for(list<ContactPerson *>::iterator i = contact_person_list.begin(); i != contact_person_list.end(); ++i) {
        ContactPerson *contact_person = *i;

        if (contact_person->getId() == contact_person_id) {
            break;
        }

        row++;
    }

    return row;
}

ContactPerson *Widget::getContactPersonById(int contact_person_id)
{
    for(list<ContactPerson *>::iterator i = contact_person_list.begin(); i != contact_person_list.end(); ++i) {
        ContactPerson *contact_person = *i;

        if (contact_person->getId() == contact_person_id) {
            return contact_person;
        }
    }

    return nullptr;
}

void Widget::showTableViewAllRow()
{
    for (int i = 1; i <= contact_person_list.size(); ++i) {
        table_view->setRowHidden(i, false);
    }
}

void Widget::getDatabaseAllData()
{
    QSqlQuery query = mysql->query;

    QString sql = "select * from contact_person";
    bool result = query.exec(sql);

    if (result) {
        while (query.next()) {
            ContactPerson *person = new ContactPerson;

            int id = query.value("id").toInt();
            person->setId(id);

            string name = query.value("name").toString().toUtf8().data();
            person->setName(name);

            int sex = query.value("sex").toInt();
            person->setSex(sex);

            int age = query.value("age").toInt();
            person->setAge(age);

            int phone = query.value("phone").toInt();
            person->setPhone(phone);

            string address = query.value("address").toString().toUtf8().data();
            person->setAddress(address);

            contact_person_list.push_back(person);
            show_person_id_list.push_back(person->getId());
        }
    }
}

void Widget::fillTableViewAddContactPersonId(ContactPerson *person)
{
    QSqlQuery query = mysql->query;
    QString sql = "select id from contact_person where phone = ?";
    query.prepare(sql);

    QString phone = QString::fromStdString(to_string(person->getPhone()));
    query.addBindValue(phone);

    bool result = query.exec();

    if (result) {
        query.next();

        int id = query.value("id").toInt();
        int row = contact_person_list.size();

        person->setId(id);

        QStandardItem *id_item = new QStandardItem(QString::fromStdString(to_string(person->getId())));
        id_item->setTextAlignment(Qt::AlignCenter);
        data_model->setItem(row, 1, id_item);
    }
}


void Widget::startClient()
{
    server_port = SERVER_PORT;

    server_ip.setAddress(QString::fromStdString(SERVER_IP));

    tcp_socket.connectToHost(server_ip, server_port);

    isStartServer = tcp_socket.isOpen();

    if (isStartServer) {
        connect(&tcp_socket, &QTcpSocket::readyRead, this, [=]() {
            QString public_key = QString(tcp_socket.readAll());

            receive_msg = QString::fromStdString(NetworkTools::decryptionMessage(public_key.toStdString()));
        });

        getUserId(); // 提前获取一次用户的ID

    } else {
        QMessageBox::information(this, "Tips", "Connect Server Fail!");
    }
}

void Widget::endClient()
{
    tcp_socket.close();
}

int Widget::getUserId()
{
    int userId = 0;

    if (isStartServer) {
        sendMessage("Get:UserID!");
        userId = receive_msg.toInt();

    } else {
        userId = qrand() % 900000 + 100000;
    }

    return userId;
}

void Widget::sendMessage(QString msg)
{
    QString public_key = QString::fromStdString(NetworkTools::encryptionMessage(msg.toStdString()));

    tcp_socket.write(public_key.toUtf8());
}


void Widget::createTargetDir()
{
    // 判断是否存在 C:\\ProgramData\\Blue\\Address Book 路径下的文件夹, 不存在就创建
    QDir dir;
    QString dir_pathname;

    dir_pathname = "C:\\ProgramData\\Blue";
    dir = QDir(dir_pathname);
    if (!dir.exists()) {
        dir.mkdir(dir_pathname);
    }

    dir_pathname += "\\Address Book";
    dir = QDir(dir_pathname);
    if (!dir.exists()) {
        dir.mkdir(dir_pathname);
    }
}

void Widget::readDataFromJson()
{
    // 不存在目标文件夹时, 需要创建对应的文件夹
    if (!QDir(QString(PROJECT_DIR_PATHNAME)).exists()) {
        createTargetDir();
    }

    QFile file(QString(PROJECT_DIR_PATHNAME) + "\\Data.json");
    file.open(QIODevice::ReadWrite);
    QByteArray json = file.readAll();
    QJsonDocument document = QJsonDocument::fromJson(json);
    contact_person_json_array = document.array();
    file.close();
}

void Widget::writeDataToJson()
{
    QJsonDocument document(contact_person_json_array);
    QByteArray json = document.toJson();
    QFile file(QString(PROJECT_DIR_PATHNAME) + "\\Data.json");
    file.open(QFile::WriteOnly);
    file.write(json);
    file.close();
}

void Widget::getJsonFileAllData()
{
    readDataFromJson();

    for (int i = 0; i < contact_person_json_array.size(); i++) {
        QJsonValue value = contact_person_json_array[i];
        QJsonObject object = value.toObject();
        ContactPerson *person = changeJsonObjectToContectPerson(object);

        contact_person_list.push_back(person);
        show_person_id_list.push_back(person->getId());
    }
}


void Widget::addContactPersonToJsonArray(ContactPerson *person)
{
    QJsonObject object;

    object.insert("id", QJsonValue(person->getId()));
    object.insert("name", QJsonValue(QString::fromStdString(person->getName())));
    object.insert("sex", QJsonValue(person->getSex()));
    object.insert("age", QJsonValue(person->getAge()));
    object.insert("phone", QJsonValue(person->getPhone()));
    object.insert("address", QJsonValue(QString::fromStdString(person->getAddress())));

    contact_person_json_array.push_back(object);
}

void Widget::deleteContactPersonFromJsonArray(ContactPerson *person)
{
    for (int i = 0; i < contact_person_json_array.size(); i++) {
        QJsonValue value = contact_person_json_array[i];
        QJsonObject object = value.toObject();

        int contact_person_id = object["id"].toInt();
        if (contact_person_id == person->getId()) {
            contact_person_json_array.removeAt(i);
        }
    }
}

ContactPerson *Widget::changeJsonObjectToContectPerson(QJsonObject &object)
{
    ContactPerson *person = new ContactPerson();

    person->setId(object["id"].toInt());
    person->setName(object["name"].toString().toStdString());
    person->setSex(object["sex"].toInt());
    person->setAge(object["age"].toInt());
    person->setPhone(object["phone"].toInt());
    person->setAddress(object["address"].toString().toStdString());

    return person;
}
